﻿using System;
using System.Drawing;
using System.Windows.Forms;
using SpriteAnimator.Classes;

namespace SpriteAnimator
{
    /// <summary>
    /// Form pour la saisie des frames
    /// </summary>
    public partial class frmFrameEdit : Form
    {
        #region Variables d'instances

        private Image m_oTexture;
        private Rectangle m_oFrame;

        #endregion

        #region Constructeurs

        /// <summary>
        /// Constructeur de la fenêtre
        /// </summary>
        /// <param name="p_oFrame">Définition de la frame</param>
        /// <param name="p_oTexture">Texture liée à la frame</param>
        public frmFrameEdit(Rectangle? p_oFrame, Image p_oTexture, Color p_oBackColor)
        {
            this.InitializeComponent();

            // *** Initialisation ***

            this.DialogResult = DialogResult.Cancel;
            this.m_oTexture = p_oTexture;
            this.chkCadre.Checked = Utils.GetRegistryValue("SpriteRectangle", "1", Utils.REGISTRY_KEY).Equals("1");
            this.picPreview.BackColor = p_oBackColor;

            if ( p_oFrame != null )
            {
                this.m_oFrame = p_oFrame.Value;
                this.PreviewFrame();

                // *** Mise à jour des textbox ***

                this.txtX.Text = this.m_oFrame.X.ToString();
                this.txtY.Text = this.m_oFrame.Y.ToString();
                this.txtWidth.Text = this.m_oFrame.Width.ToString();
                this.txtHeight.Text = this.m_oFrame.Height.ToString();
            }
            else
                this.m_oFrame = new Rectangle();

            // *** Info texture ***

            this.lblInformation.Text = String.Format("Information texture : {0} x {1}", this.m_oTexture.Width, this.m_oTexture.Height);
        }

        #endregion

        #region Evénements de l'application

        /// <summary>
        /// Sur le click visualisation
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void cmdVisu_Click(object sender, EventArgs e)
        {
            this.PreviewFrame();
        }

        /// <summary>
        /// Annule la saisie
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void cmdCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        /// <summary>
        /// Valide la saisie
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void cmdOk_Click(object sender, EventArgs e)
        {
            // *** Vérification ***

            if ( !this.VerifyBounds() )
            {
                MessageBox.Show(this, "Les données que vous avez saisie sont incorectes.", "Avertissement", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // *** Valide ***

            this.DialogResult = DialogResult.OK;
            this.Close();
        }

        /// <summary>
        /// Active ou non le cadre de rendu
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void chkCadre_CheckedChanged(object sender, EventArgs e)
        {
            this.PreviewFrame();
        }

        /// <summary>
        /// Saisie d'une donnée
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void txtX_TextChanged(object sender, EventArgs e)
        {
            int iParse = 0;
            TextBox oBox = (TextBox)sender;

            if ( !string.IsNullOrEmpty(oBox.Text) && !int.TryParse(oBox.Text, out iParse) )
                oBox.Text = this.m_oFrame.X.ToString();
            else if ( !string.IsNullOrEmpty(oBox.Text) )
                this.m_oFrame.X = iParse;
            else
                this.m_oFrame.X = 0;
        }

        /// <summary>
        /// Saisie d'une donnée
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void txtY_TextChanged(object sender, EventArgs e)
        {
            int iParse = 0;
            TextBox oBox = (TextBox)sender;

            if ( !string.IsNullOrEmpty(oBox.Text) && !int.TryParse(oBox.Text, out iParse) )
                oBox.Text = this.m_oFrame.Y.ToString();
            else if ( !string.IsNullOrEmpty(oBox.Text) )
                this.m_oFrame.Y = iParse;
            else
                this.m_oFrame.Y = 0;
        }

        /// <summary>
        /// Saisie d'une donnée
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void txtWidth_TextChanged(object sender, EventArgs e)
        {
            int iParse = 0;
            TextBox oBox = (TextBox)sender;

            if ( !string.IsNullOrEmpty(oBox.Text) && !int.TryParse(oBox.Text, out iParse) )
                oBox.Text = this.m_oFrame.Width.ToString();
            else if ( !string.IsNullOrEmpty(oBox.Text) )
                this.m_oFrame.Width = iParse;
            else
                this.m_oFrame.Width = 0;
        }

        /// <summary>
        /// Saisie d'une donnée
        /// </summary>
        /// <param name="sender">Source de l'appel</param>
        /// <param name="e">Argument de l'appel</param>
        private void txtHeight_TextChanged(object sender, EventArgs e)
        {
            int iParse = 0;
            TextBox oBox = (TextBox)sender;

            if ( !string.IsNullOrEmpty(oBox.Text) && !int.TryParse(oBox.Text, out iParse) )
                oBox.Text = this.m_oFrame.Height.ToString();
            else if ( !string.IsNullOrEmpty(oBox.Text) )
                this.m_oFrame.Height = iParse;
            else
                this.m_oFrame.Height = 0;
        }

        #endregion

        #region Fonctions privées

        /// <summary>
        /// Lance la prévisualisation de la frame
        /// </summary>
        private void PreviewFrame()
        {
            // *** Libération de l'ancienne image ***

            if ( this.picPreview.Image != null )
            {
                this.picPreview.Image.Dispose();
                this.picPreview.Image = null;
            }

            // *** Vérification ***

            if ( this.VerifyBounds() )
            {
                // *** Génération de l'image ***

                Bitmap oImg = new Bitmap(this.m_oFrame.Width, this.m_oFrame.Height);

                // *** On récupère la zone de dessin ***

                using ( Graphics oGraphics = Graphics.FromImage(oImg) )
                {
                    // *** Ecriture de l'image ***

                    oGraphics.DrawImage(this.m_oTexture, new Rectangle(0, 0, this.m_oFrame.Width, this.m_oFrame.Height), this.m_oFrame, GraphicsUnit.Pixel);

                    // *** Cadre ***

                    if ( this.chkCadre.Checked )
                    {
                        using ( Pen oPen = new Pen(Color.Black) )
                        {
                            oGraphics.DrawRectangle(oPen, new Rectangle(0, 0, this.m_oFrame.Width - 1, this.m_oFrame.Height - 1));
                        }
                    }
                }

                // *** Ajout au contrôle ***

                this.picPreview.Image = oImg;
            }

            // *** Ré affichage ***

            this.picPreview.Invalidate();
        }

        /// <summary>
        /// V2rifie si les informations données sont correctes
        /// </summary>
        /// <returns>TRUE information correcte, FALSE sinon</returns>
        private bool VerifyBounds()
        {
            // *** Vérifiation des bornes X et Y ***

            if ( this.m_oFrame.X < 0 || this.m_oFrame.Y < 0 )
                return (false);

            if ( this.m_oFrame.X > this.m_oTexture.Width || this.m_oFrame.Y > this.m_oTexture.Height )
                return (false);

            // *** Vérification de la taille ***

            if ( this.m_oFrame.Width < 1 || this.m_oFrame.Width > this.m_oTexture.Width )
                return (false);

            if ( this.m_oFrame.Height < 1 || this.m_oFrame.Height > this.m_oTexture.Height )
                return (false);

            // *** Vérification terminée ***

            return (true);
        }

        #endregion

        #region Indexer

        /// <summary>
        /// Retourne la frame en cours de sélection
        /// </summary>
        public Rectangle Frame
        {
            get
            {
                return (this.m_oFrame);
            }
        }

        #endregion
    }
}
